package logic

import (
	"bookmark-web/dao"
	"bookmark-web/models"
	"errors"
	"gorm.io/gorm"
	"log"
	"strings"
)

// CreateCategory 创建分类业务逻辑
func CreateCategory(req *models.CategoryCreateRequest, userID uint) (*models.CategoryResponse, error) {
	// 1. 检查分类名称是否已存在（同一父分类下不能重名）
	exists, err := dao.CheckCategoryExists(req.Name, req.ParentID, userID)
	if err != nil {
		return nil, errors.New("检查分类名称失败")
	}
	if exists {
		return nil, errors.New("该分类名称已存在")
	}

	// 2. 如果有父分类，检查父分类是否存在且属于当前用户
	if req.ParentID != nil {
		_, err := dao.GetCategoryByID(*req.ParentID, userID)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, errors.New("父分类不存在")
			}
			return nil, errors.New("查询父分类失败")
		}
	}

	// 3. 获取分类层级
	level := dao.GetCategoryLevel(req.ParentID)

	// 4. 创建分类对象
	category := models.Category{
		Name:     req.Name,
		ParentID: req.ParentID,
		Level:    level,
		UserID:   userID,
	}

	// 5. 保存到数据库
	err = dao.CreateCategory(&category)
	if err != nil {
		return nil, errors.New("创建分类失败")
	}

	// 6. 构建分类路径
	path, err := dao.BuildCategoryPath(category)
	if err != nil {
		// 路径构建失败不影响分类创建，只记录错误
		path = category.Name
	}

	// 7. 更新分类路径
	category.Path = path
	err = dao.UpdateCategory(&category)
	if err != nil {
		// 路径更新失败不影响分类创建
	}

	// 8. 重新获取分类信息（包含关联数据）
	createdCategory, err := dao.GetCategoryByID(category.ID, userID)
	if err != nil {
		return nil, errors.New("获取创建的分类失败")
	}

	return createdCategory.ToResponse(), nil
}

// GetCategoryByID 根据ID获取分类
func GetCategoryByID(id uint, userID uint) (*models.CategoryResponse, error) {
	category, err := dao.GetCategoryByID(id, userID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("分类不存在")
		}
		return nil, errors.New("查询分类失败")
	}
	return category.ToResponse(), nil
}

// GetCategoriesList 获取分类列表（分页）
func GetCategoriesList(userID uint, req *models.CategoryQueryRequest) (*models.CategoryListResponse, error) {
	// 设置默认值
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 10
	}

	// 获取分类列表
	categories, total, err := dao.GetCategoriesByUserID(userID, req.Page, req.PageSize, req.Search)
	if err != nil {
		return nil, errors.New("获取分类列表失败")
	}

	// 转换为响应格式
	categoryResponses := make([]*models.CategoryResponse, len(categories))
	for i, category := range categories {
		categoryResponses[i] = category.ToResponse()
	}

	// 计算总页数
	totalPages := int(total) / req.PageSize
	if int(total)%req.PageSize > 0 {
		totalPages++
	}

	return &models.CategoryListResponse{
		Categories: categoryResponses,
		Total:      total,
		Page:       req.Page,
		PageSize:   req.PageSize,
		TotalPages: totalPages,
	}, nil
}

// GetCategoryTree 获取分类树
func GetCategoryTree(userID uint) ([]*models.CategoryTreeResponse, error) {
	categories, err := dao.GetCategoryTree(userID)
	if err != nil {
		return nil, errors.New("获取分类树失败")
	}

	// 转换为树形响应格式
	treeResponses := make([]*models.CategoryTreeResponse, len(categories))
	for i, category := range categories {
		treeResponses[i] = category.ToTreeResponse()
	}

	return treeResponses, nil
}

// UpdateCategory 更新分类
func UpdateCategory(id uint, req *models.CategoryUpdateRequest, userID uint, parentID uint) (*models.CategoryResponse, error) {
	// 1. 获取原分类信息，检查分类是否存在。结合缓存手段可以减轻数据库压力
	category, err := dao.GetCategoryByID(id, userID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("分类不存在")
		}
		return nil, errors.New("查询分类失败")
	}
	// 保存原始分类名称
	oldName := category.Name

	// 比较父分类id，判断是否修改当前分类的父分类
	oldParentID := uint(0)
	if category.ParentID != nil {
		oldParentID = *category.ParentID
	}
	if oldParentID != parentID {
		// 修改当前分类的父分类
		category.ParentID = &parentID
	}

	// 2. 检查新名称是否与其他分类重复
	exists, err := dao.CheckCategoryExists(req.Name, category.ParentID, userID, id)
	if err != nil {
		return nil, errors.New("检查分类名称失败")
	}
	if exists {
		return nil, errors.New("该分类名称已存在")
	}

	// 3. 更新分类信息
	category.Name = req.Name

	// 存储旧的路径
	oldPath := category.Path

	// 4. 重新构建路径
	// 安全地比较 ParentID，处理 nil 指针情况
	parentIDChanged := false
	if category.ParentID == nil {
		// 如果当前 ParentID 为 nil，只有当 oldParentID 不为 0 时才算改变
		parentIDChanged = oldParentID != 0
	} else {
		// 如果当前 ParentID 不为 nil，直接比较值
		parentIDChanged = oldParentID != *category.ParentID
	}
	// 分类名称和父分类没变，近修改了其它字段，则不需要重新构建路径。其它情况都需要重构路径
	if oldName != category.Name || parentIDChanged {
		//path, err := dao.BuildCategoryPath(category.ID, *category.ParentID)
		path, err := dao.BuildCategoryPath(category)
		if err == nil {
			category.Path = path
		}
	}

	// 5. 保存更新
	err = dao.UpdateCategory(&category)
	if err != nil {
		return nil, errors.New("更新分类失败")
	}

	// 6. 如果有子分类，需要更新所有子分类的路径
	if oldName != category.Name || parentIDChanged {
		// 父分类改变或者分类名称改变才更新子分类路径
		updateChildrenPaths(&category, oldPath)
	}

	// 7. 重新获取分类信息
	updatedCategory, err := dao.GetCategoryByID(id, userID)
	if err != nil {
		return nil, errors.New("获取更新后的分类失败")
	}

	return updatedCategory.ToResponse(), nil
}

// updateChildrenPaths 递归更新子分类路径
//func updateChildrenPaths(parentID uint, userID uint) error {
//	children, err := dao.GetCategoriesByParentID(&parentID, userID)
//	if err != nil {
//		return err
//	}
//
//	for _, child := range children {
//		// 重新构建路径
//		path, err := dao.BuildCategoryPath(child.ID, parentID)
//		if err == nil {
//			child.Path = path
//			dao.UpdateCategory(child)
//		}
//
//		// 递归更新子分类的子分类
//		updateChildrenPaths(child.ID, userID)
//	}
//
//	return nil
//}

func updateChildrenPaths(category *models.Category, oldPath string) {
	// 获取当前分类的完整路径
	newPath := category.Path
	// 迭代子分类，更换前面的分类路径
	for _, child := range category.Children {
		// 查询数据库
		child, err := dao.GetCategoryByID(child.ID, category.UserID)
		if err != nil {
			log.Printf("Error getting category: %v", err)
		}
		// 获取子分类路径
		path := child.Path
		// 替换分类前面的路径
		child.Path = strings.Replace(path, oldPath, newPath, 1)
		// 保存数据库
		dao.UpdateCategory(&child)
		// 递归更新子分类的子分类的路径
		updateChildrenPaths(&child, path)
	}
}

// DeleteCategory 删除分类
func DeleteCategory(id uint, userID uint) error {
	// 1. 检查分类是否存在
	_, err := dao.GetCategoryByID(id, userID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("分类不存在")
		}
		return errors.New("查询分类失败")
	}

	// 2. 删除分类（会级联删除子分类）
	err = dao.DeleteCategory(id, userID)
	if err != nil {
		errStr := err.Error()
		if strings.Contains(errStr, "请先删除网址") {
			return errors.New("当前分类或其子分类下有网址关联，请先删除网址")
		} else {
			return errors.New("删除分类失败")
		}
	}

	return nil
}

// SearchCategories 搜索分类
func SearchCategories(userID uint, keyword string, page, pageSize int) (*models.CategoryListResponse, error) {
	// 设置默认值
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 10
	}

	// 搜索分类
	categories, total, err := dao.SearchCategories(userID, keyword, page, pageSize)
	if err != nil {
		return nil, errors.New("搜索分类失败")
	}

	// 转换为响应格式
	categoryResponses := make([]*models.CategoryResponse, len(categories))
	for i, category := range categories {
		categoryResponses[i] = category.ToResponse()
	}

	// 计算总页数
	totalPages := int(total) / pageSize
	if int(total)%pageSize > 0 {
		totalPages++
	}

	return &models.CategoryListResponse{
		Categories: categoryResponses,
		Total:      total,
		Page:       page,
		PageSize:   pageSize,
		TotalPages: totalPages,
	}, nil
}
